package com.rongzhe.house.common.utils;

import com.google.gson.Gson;
import com.qiniu.common.Zone;
import com.qiniu.http.Response;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import com.rongzhe.house.common.constants.Constants;
import com.rongzhe.house.common.exception.RongZheBusinessException;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.lang3.RandomUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.*;

/**
 * Created by JackWangon[www.coder520.com] 2017/8/4.
 */
public class QiniuFileUploadUtil {


    public static ExecutorService executorService = Executors.newFixedThreadPool(100);


    public static String uploadHeadImg(MultipartFile file) throws IOException {

        Configuration cfg = new Configuration(Zone.zone2());
        UploadManager uploadManager = new UploadManager(cfg);
        Auth auth = Auth.create(Constants.QINIU_ACCESS_KEY, Constants.QINIU_SECRET_KEY);
        String upToken = auth.uploadToken(Constants.QINIU_HEAD_IMG_BUCKET_NAME);
        String fileExtension = FileUtils.getFileExtension(file.getOriginalFilename());
        String s = MD5(file.getInputStream());
        Response response = uploadManager.put(file.getBytes(), s + "." + fileExtension, upToken);
        //解析上传成功的结果
        DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
        return putRet.key;
    }

    /**
     * 获取输入流的md5
     *
     * @param inputStream 输入流
     * @return md5 值
     */
    public static String MD5(InputStream inputStream) {
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            byte[] buffer = new byte[8192];
            int length;
            while ((length = inputStream.read(buffer)) != -1) {
                md5.update(buffer, 0, length);
            }
            return new String(Hex.encodeHex(md5.digest()));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            try {
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static String uploadContract(byte[] file, String fileName) throws IOException {
        Configuration cfg = new Configuration(Zone.zone2());
        UploadManager uploadManager = new UploadManager(cfg);
        Auth auth = Auth.create(Constants.QINIU_ACCESS_KEY, Constants.QINIU_SECRET_KEY);
        String upToken = auth.uploadToken(Constants.QINIU_CONTRACT_BUCKET);
        Response response = uploadManager.put(file, fileName, upToken);
        //解析上传成功的结果md
        DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
        return Constants.QINIU_PROTOCOL + Constants.QINIU_CONTRACT_BUCKET_URL + "/" + putRet.key;
    }

    public static List<String> uploadHeadImgList(MultipartFile[] files) throws IOException, InterruptedException, ExecutionException {


        if (files.length > 9) {
            //最大
            throw new RongZheBusinessException("图片数量最大为9张");
        }
        List<String> imgUrls = new ArrayList<>(files.length);
        Configuration cfg = new Configuration(Zone.zone2());

        UploadManager uploadManager = new UploadManager(cfg);
        Auth auth = Auth.create(Constants.QINIU_ACCESS_KEY, Constants.QINIU_SECRET_KEY);
        String upToken = auth.uploadToken(Constants.QINIU_HEAD_IMG_BUCKET_NAME);

        //将执行的结果放入一个阻塞队列
        ExecutorCompletionService<Uploader.DefaultPutRetAndIndex> executorCompletionService = new ExecutorCompletionService(executorService);

        for (int i = 0; i < files.length; i++) {
            executorCompletionService.submit(new Uploader(files[i], uploadManager, upToken, i));
        }

        List<Uploader.DefaultPutRetAndIndex> defaultPutRetAndIndices = new ArrayList<>();
        for (int i = 0; i < files.length; i++) {
            defaultPutRetAndIndices.add(executorCompletionService.take().get());
        }
        //保证跟客户端上传的顺序一样
        Collections.sort(defaultPutRetAndIndices);


        defaultPutRetAndIndices.forEach(defaultPutRetAndIndex -> {
            imgUrls.add(Constants.QINIU_PROTOCOL + Constants.QINIU_HEAD_IMG_BUCKET_URL + "/" + defaultPutRetAndIndex.putRet.key);
        });


        return imgUrls;
    }

    /**
     * 实现带参数返回的结果
     */
    public static class Uploader implements Callable<Uploader.DefaultPutRetAndIndex> {

        private MultipartFile multipartFile;

        private UploadManager uploadManager;

        private String upToken;

        /**
         * 记录上传的顺序
         */
        private int index;

        public Uploader(MultipartFile multipartFile, UploadManager uploadManager, String upToken, int index) {
            this.multipartFile = multipartFile;
            this.uploadManager = uploadManager;
            this.upToken = upToken;
            this.index = index;
        }

        @Override
        public DefaultPutRetAndIndex call() throws Exception {

            Response response = uploadManager.put(multipartFile.getBytes(), System.nanoTime() + "" + RandomUtils.nextInt(0, 100) + index, upToken);
            //解析上传成功的结果
            DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);

            return new DefaultPutRetAndIndex(this.index, putRet);
        }


        //封装顺序
        public static class DefaultPutRetAndIndex implements Comparable<DefaultPutRetAndIndex> {

            private int index;

            private DefaultPutRet putRet;

            public DefaultPutRetAndIndex(int index, DefaultPutRet putRet) {
                this.index = index;
                this.putRet = putRet;
            }


            //重写比较
            @Override
            public int compareTo(DefaultPutRetAndIndex o) {

                if (o == this) {
                    return 0;
                }

                return this.index - o.index;
            }


        }
    }

}
